package com.wwf.sqlsession;
import com.wwf.pojo.Configuration;
import com.wwf.pojo.MappedStatement;
import com.wwf.utils.GenericTokenParser;
import com.wwf.utils.ParameterMapping;
import com.wwf.utils.ParameterMappingTokenHandler;
import javax.sql.DataSource;
import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class SimpleSqlExecutor implements SqlExecutor{
    @Override
    public <E> List<E> query(Configuration configuration, MappedStatement mappedStatement, Object... parameters) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InstantiationException, InvocationTargetException, IntrospectionException {
        //获取数据源并建立数据库连接
        PreparedStatement preparedStatement = this.getPreparedStatement(configuration, mappedStatement, parameters);
        //执行sql并封装返回值
        String resultType = mappedStatement.getResultType();
        Class<?> resultClassType = getClassType(resultType);
        ResultSet resultSet = preparedStatement.executeQuery();
        ArrayList<Object> objects = new ArrayList<>();
        while (resultSet.next()) {
            Object o = resultClassType.newInstance();
            ResultSetMetaData metaData = resultSet.getMetaData();
            for (int i = 1; i <= metaData.getColumnCount(); i++) {
                String columnName = metaData.getColumnName(i);
                Object value = resultSet.getObject(columnName);
                PropertyDescriptor propertyDescriptor = new PropertyDescriptor(columnName, resultClassType);
                Method writeMethod = propertyDescriptor.getWriteMethod();
                writeMethod.invoke(o, value);
            }
            objects.add(o);
        }
        return (List<E>) objects;
    }



    @Override
    public int insert(Configuration configuration, MappedStatement mappedStatement, Object... parameters) throws SQLException, NoSuchFieldException, ClassNotFoundException, IllegalAccessException {
        int efectNum=0;
        PreparedStatement preparedStatement = this.getPreparedStatement(configuration, mappedStatement, parameters);
        return preparedStatement.executeUpdate();

    }

    @Override
    public int update(Configuration configuration, MappedStatement mappedStatement, Object... parameters) throws NoSuchFieldException, SQLException, ClassNotFoundException, IllegalAccessException {
        int efectNum=0;
        PreparedStatement preparedStatement = this.getPreparedStatement(configuration, mappedStatement, parameters);
        return preparedStatement.executeUpdate();
    }

    @Override
    public int deleteById(Configuration configuration, MappedStatement mappedStatement, Object... parameters) throws SQLException, NoSuchFieldException, ClassNotFoundException, IllegalAccessException {
        int efectNum=0;
        PreparedStatement preparedStatement = this.getPreparedStatement(configuration, mappedStatement, parameters);
        return preparedStatement.executeUpdate();
    }

    private Class<?> getClassType(String parameterType) throws ClassNotFoundException {
        if(parameterType !=null) {
            Class<?> aClass = Class.forName(parameterType);
            return  aClass;
        }
        return null;
    }

     BoundSql getBoundSql(String sql) {
        //创建标记解析器处理类完成对sql标记的解析处理工作
        ParameterMappingTokenHandler parameterMappingTokenHandler = new ParameterMappingTokenHandler();
        GenericTokenParser genericTokenParser = new GenericTokenParser("#{", "}", parameterMappingTokenHandler);
        String boundsql = genericTokenParser.parse(sql);
        List<ParameterMapping> parameterMappings = parameterMappingTokenHandler.getParameterMappings();
        BoundSql boundSql = new BoundSql(boundsql, parameterMappings);
        return boundSql;
    }
    protected PreparedStatement getPreparedStatement(Configuration configuration, MappedStatement mappedStatement, Object... parameters) throws SQLException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        //获取数据源并建立数据库连接
        DataSource dataSource = configuration.getDataSource();
        Connection connection = dataSource.getConnection();
        //获取sql
        String sql = mappedStatement.getSqlTex();
        BoundSql boundSql = this.getBoundSql(sql);
        //获取 PreparedStatement 并赋值参数
        PreparedStatement preparedStatement = connection.prepareStatement(boundSql.getBoundsql());
        String parameterType = mappedStatement.getParameterType();
        Class<?> parameterTypeClass = getClassType(parameterType);
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        for (int i = 0; i <parameterMappings.size() ; i++) {
            ParameterMapping parameterMapping =  parameterMappings.get(i);
            String content = parameterMapping.getContent();
            if(parameterTypeClass != null){
                Field declaredField = parameterTypeClass.getDeclaredField(content);
                declaredField.setAccessible(true);
                Object o = declaredField.get(parameters[0]);
                preparedStatement.setObject(i+1,o);
            }

        }
        return preparedStatement;
    }
}
